package com.af.security.auth.login.service;

import com.af.security.auth.user.detail.AfUserDetails;
import com.af.security.auth.user.detail.AuthMenu;
import com.af.security.auth.user.detail.AuthRole;
import com.af.security.auth.user.detail.AuthUser;
import com.af.security.mgt.permisson.Permission;
import com.af.security.mgt.role.Role;
import com.af.security.mgt.user.User;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.yitter.idgen.YitIdHelper;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * @author : zhenyun.su
 * @commit: 构建UserDetails的实现类AfUserDetails， 用于在登录请求/perform_login触发身份验证
 * @since : 2020/03/25
 */

@Service
public class AfUserDetailsService implements UserDetailsService {
    private static final Logger logger = LoggerFactory.getLogger(AfUserDetailsService.class);
    @Autowired
    private AfAuthDataService afAuthDataService;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private Cache<String, AfUserDetails> securityCache;

    /**
     * @comment : 加载用户，角色，权限，菜单数据，开发测试时，屏蔽缓存
     */
    @Override
    public AfUserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        logger.debug("loadUserByUsername, according to {}", s);

        logger.debug("loadUserByUsername, get user from cache");
        AfUserDetails userDetails = securityCache.getIfPresent(s);
        if (ObjectUtils.isEmpty(userDetails)){
            logger.debug("loadUserByUsername, get user from database");
            User user = afAuthDataService.getUserInfo(s);
            if (user == null) {
                throw new UsernameNotFoundException("can not found " + s);
            }
            logger.debug("loadUserByUsername, {}", user);

            logger.debug("loadUserByUsername, get permission from database");
            List<Permission> permissions = afAuthDataService.getAllPermission(user.getId());
            logger.debug("loadUserByUsername, get permissions finish, {}", permissions);

            logger.debug("loadUserByUsername, get operation from database");
            List<String> operateCodes = afAuthDataService.getAllOperateCode(permissions);
            logger.debug("loadUserByUsername, get operation finish, {}", operateCodes);

            logger.debug("loadUserByUsername, build SzyUserDetails");
            userDetails= new AfUserDetails(buildAuthUser(user), user.getPassword(),
                    operateCodes, buildAuthRoles(user), buildAuthMenus(permissions));
            securityCache.put(s, userDetails);
        }
        return userDetails;
    }

    /*
     * @comment : 基于手机号来获取用户
     */
    public AfUserDetails loadUserByPhone(String phone) throws UsernameNotFoundException {
        logger.debug("loadUserByPhone, according to {}", phone);
        User user = afAuthDataService.getUserFromPhone(phone);
        if (user == null) {
            throw new UsernameNotFoundException("can not found " + phone);
        }
        return loadUserByUsername(user.getUsername());
    }

    /*
     * @comment : 基于邮箱地址来获取用户，并注册用户
     * sourceId: 为ad或ldap的用户身份标识
     */
    public AfUserDetails ldapLoginSuccessAndUpdateAccount(String name, String password, String sourceId) throws UsernameNotFoundException {
        User user = afAuthDataService.getUserBySourceId(sourceId);
        if (user == null) {
            String pass = (password != null) ? passwordEncoder.encode(password) : "";
            user = User.of(YitIdHelper.nextId(), name, pass, "", "","", "", sourceId, User.SOURCE_TYPE_AD, true);
        } else {
            user.setUsername(name);
        }
        user = afAuthDataService.saveAccount(user);
        return loadUserByUsername(user.getUsername());
    }

    private AuthUser buildAuthUser(User user) {
        AuthUser authUser = new AuthUser();
        BeanUtils.copyProperties(user, authUser);
        return authUser;
    }

    private List<AuthRole> buildAuthRoles(User user) {
        List<AuthRole> authRoles = new ArrayList<>();
        for (Role role : user.getRoles()) {
            AuthRole authRole = new AuthRole();
            BeanUtils.copyProperties(role, authRole);
            authRoles.add(authRole);
        }
        return authRoles;
    }

    private List<AuthMenu> buildAuthMenus(List<Permission> permissions) {
        AfMenuService menuService = new AfMenuService(permissions);
        List<AuthMenu> authMenus = menuService.getMenuTree();
        return authMenus;
    }

}
